package cn.lb.permission.service.impl;


import cn.lb.annotation.LBPermission;
import cn.lb.permission.domain.Permission;
import cn.lb.permission.mapper.PermissionMapper;
import cn.lb.permission.service.IPermissionScanService;
import cn.lb.basic.util.ClassUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

@Service
public class PermissionScanServiceImpl implements IPermissionScanService {

    @Value("${lb.permission.scanPackage}")
    private String scanPackage;

    @Autowired
    private PermissionMapper permissionMapper;

    /**
     * 容器启动,权限扫描
     */
    @Override
    public void scan() {
        // 1 扫描controller这个包下面所有的Controller类 - 获取controller包下所有的类
        List<Class> classes = ClassUtils.getAllClassName(this.scanPackage);
        List<Permission> permissions = new ArrayList<>();
        // 2 循环所有的Controller
        for (Class aClass : classes) {
            // 3 判断Controller类上是否有自定义注解,
            LBPermission classAnnotation = (LBPermission)aClass.getAnnotation(LBPermission.class);
            if(Objects.isNull(classAnnotation)){
                //如果类上面没有自定义注解就说明当前这个类里面的方法都不需要权限就能访问,就直接跳过,不需要再去处理方法了
                continue;
            }
            // 4 将类上面的注解也解析成一个Permission对象,作为方法权限对象的父亲
            Permission parent = new Permission();
            parent.setName(classAnnotation.name());
            parent.setDescs(classAnnotation.descs());
            // 取类的url
            RequestMapping classRequestMapping = (RequestMapping)aClass.getAnnotation(RequestMapping.class);
            if(Objects.nonNull(classRequestMapping)){
                parent.setUrl(classRequestMapping.value()[0]);
            }
            parent.setSn(aClass.getSimpleName());
            permissions.add(parent);
            // 如果有自定义注解,就说明这个类里面的方法需要权限才能访问
            // 4 获取这个类里面所有的方法(反射)
            Method[] methods = aClass.getMethods();
            for (Method method : methods) {
                // 5 判断方法上面有没有自定义注解
                LBPermission methodAnnotation = method.getAnnotation(LBPermission.class);
                if(Objects.isNull(methodAnnotation)){
                    continue;   // 如果没有自定义注解,就说明该接口不需要权限来访问,就直接跳过不处理
                }
                // 6 如果有注解,就封装Permission对象,并存到数据库的t_permission表中
                // 一个@RonghuaPermission就有一个Permission对象
                Permission permission = new Permission();
                permission.setName(methodAnnotation.name());
                permission.setDescs(methodAnnotation.descs());
                // url  类上面的 url + 方法上面的url
                permission.setUrl(getUrl(aClass, method));
                // sn   类名:方法名
                permission.setSn(aClass.getSimpleName()+":"+method.getName());
                // 设置父权限对象
                permission.setParent(parent);
                permissions.add(permission);
            }
        }
        // 将封装好的Permission对象存到数据库
        // 判断权限集合是否为空,如果不为空,就要操作数据库
        // 分析,怎么判断权限在数据库是否存在? 通过sn判断  sn有就说明存在  sn没有就说明不存在
        // 1 如果sn不存在,那么就直接新增
        // 2 如果sn存在了,做修改操作
        // 3 如果之前某个sn在数据库存在,但是现在新封装的权限中,已经删除没有了怎么办?
            // 方案一: 简单粗暴  先全部删除,再全部新增,如果采用这种方案,那么就不需要修改了  - 采纳这一种
            // 方案二: 就是要先查询出数据库里面所有的权限,再跟现在新封装的权限作对比,如果数据库有而新封装的没有,就删除 - 写起来麻烦

        // 删除所有的权限
        permissionMapper.deleteAll();

        // 添加权限
        if(!CollectionUtils.isEmpty(permissions)){
            for (Permission permission : permissions) {
                permissionMapper.insert(permission);
            }
        }
    }

    private String getUrl(Class aClass,Method method){
        String url = "";
        // 获取类名的url
        RequestMapping classRequestMapping = (RequestMapping)aClass.getAnnotation(RequestMapping.class);
        if(Objects.nonNull(classRequestMapping)){
            url = classRequestMapping.value()[0];
        }
        // 获取方法的url
        GetMapping getMapping = (GetMapping)method.getAnnotation(GetMapping.class);
        if(Objects.nonNull(getMapping) && getMapping.value().length > 0){
            url += getMapping.value()[0];
        }
        PostMapping postMapping = (PostMapping)method.getAnnotation(PostMapping.class);
        if(Objects.nonNull(postMapping) && postMapping.value().length > 0){
            url += postMapping.value()[0];
        }
        PutMapping putMapping = (PutMapping)method.getAnnotation(PutMapping.class);
        if(Objects.nonNull(putMapping) && putMapping.value().length > 0){
            url += putMapping.value()[0];
        }
        DeleteMapping deleteMapping = (DeleteMapping)method.getAnnotation(DeleteMapping.class);
        if(Objects.nonNull(deleteMapping) && deleteMapping.value().length > 0){
            url += deleteMapping.value()[0];
        }
        PatchMapping patchMapping = (PatchMapping)method.getAnnotation(PatchMapping.class);
        if(Objects.nonNull(patchMapping) && patchMapping.value().length > 0){
            url += patchMapping.value()[0];
        }
        return url;
    }

    public static void main(String[] args) {
        List<Permission> permissions = new ArrayList<>();
        Permission parent = new Permission();   // 父权限
        permissions.add(parent);

        Permission permission = new Permission();   // 子权限
        permission.setParent(parent);       // 给子权限添加父权限
        permissions.add(permission);

        parent.setId(1L);       // 修改父权限
        permissions.forEach(System.out::println);
    }
}
